package com.joysuch.wwyt.attendance.excel;

import com.google.common.base.Splitter;
import com.google.common.collect.Lists;
import com.joysuch.wwyt.attendance.bean.AttendanceBaseUserExcelBean;
import com.joysuch.wwyt.attendance.bean.AttendanceDayBean;
import com.joysuch.wwyt.attendance.bean.AttendanceGroupShiftBean;
import com.joysuch.wwyt.attendance.entity.AttendanceGroup;
import com.joysuch.wwyt.attendance.entity.AttendanceShift;
import com.joysuch.wwyt.attendance.entity.AttendanceUser;
import com.joysuch.wwyt.attendance.enums.AttendanceFlagEnum;
import com.joysuch.wwyt.attendance.mapper.AttendanceGroupMapper;
import com.joysuch.wwyt.attendance.mapper.AttendanceUserMapper;
import com.joysuch.wwyt.attendance.service.AttendanceGroupService;
import com.joysuch.wwyt.attendance.service.AttendanceShiftService;
import com.joysuch.wwyt.attendance.service.AttendanceUserService;
import com.joysuch.wwyt.attendance.util.AttendanceDayUtils;
import com.joysuch.wwyt.common.constant.Constant;
import com.joysuch.wwyt.core.entity.BaseUser;
import com.joysuch.wwyt.core.enums.DeleteFlag;
import com.joysuch.wwyt.risk.service.RiskEvaluationExcelImportService;
import com.joysuch.wwyt.risk.util.RiskEvalExcelUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.streaming.SXSSFCell;
import org.apache.poi.xssf.streaming.SXSSFRow;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @Author ZhaoQiuWei
 * @Date 2022/3/8 9:20
 */
@Slf4j
@Service
public class AttendanceUserExcelServiceImpl implements AttendanceUserExcelService {

    @Autowired
    private AttendanceGroupService groupService;

    @Autowired
    private AttendanceUserService userService;

    @Autowired
    private AttendanceShiftService shiftService;

    @Autowired
    private RiskEvaluationExcelImportService riskImportService;

    @Autowired
    private AttendanceGroupMapper groupMapper;

    @Autowired
    private AttendanceUserMapper userMapper;

    private final int userNameRowIndex = 3;

    @Override
    public List<String> importUserExcel(MultipartFile file, Integer year, Integer month) {
        List<String> errorMessage = new ArrayList<>();
        boolean dateFlag = AttendanceDayUtils.getDateCheckFlag(year, month);
        try {
            XSSFWorkbook workbook = new XSSFWorkbook(file.getInputStream());
            Map<String, AttendanceGroup> nameGroupMap = new HashMap<>();
            List<AttendanceGroup> groupList = groupService.getLastGroupList();
            if (CollectionUtils.isEmpty(groupList)) {
                errorMessage.add("请先配置考勤组信息");
                return errorMessage;
            }
            nameGroupMap = groupList.stream().collect(Collectors.toMap(AttendanceGroup::getGroupName, e -> e));
            List<AttendanceDayBean> dayBeanList = AttendanceDayUtils.getDayByMonth(year, month);
            for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
                AttendanceGroup group = nameGroupMap.get(workbook.getSheetName(i));
                if (group != null) {
                    Map<String, AttendanceShift> shiftNameMap = shiftService.getShifNameMap(group);
                    if (CollectionUtils.isEmpty(shiftNameMap)) {
                        errorMessage.add("考情组 " + group.getGroupName() + ",未配置考勤班次信息");
                        continue;
                    }
                    errorMessage.addAll(importUserData(group, workbook.getSheetAt(i), year, month, dayBeanList, shiftNameMap, dateFlag));
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return errorMessage;
    }

    //人员考勤排班导入
    private List<String> importUserData(AttendanceGroup group, XSSFSheet sheet, Integer year, Integer month, List<AttendanceDayBean> dayBeanList, Map<String, AttendanceShift> shiftNameMap, boolean dateFlag) {
        List<String> errorMessage = new ArrayList<>();
        List<AttendanceUser> userList = new ArrayList<>();
        Map<String, AttendanceUser> newUserDayShiftMap = new HashMap<>();
        List<BaseUser> staffList = new ArrayList<>();
        if (dateFlag) {
            staffList = userService.getGroupStaffList(group, null, null);
        } else {
            staffList = userMapper.getAttendanceOldUserByGroupAndYearAndMonth(group.getId(), year, month);
        }
        if (CollectionUtils.isEmpty(staffList)) {
            if (dateFlag) {
                errorMessage.add(String.format(sheet.getSheetName() + "考勤组 {%s}考勤人员不能为空", sheet.getSheetName()));
            } else {
                errorMessage.add(String.format(sheet.getSheetName() + "考勤组 {%s}无排班人员", sheet.getSheetName()));
            }
            return errorMessage;
        }
        //人员map(name:id)
        Map<String, Long> userNameIdMap = new HashMap<>();
        staffList.forEach(e -> {
            userNameIdMap.put(e.getRealName(), e.getId());
        });
        //获取本月已经排好的班次
        List<AttendanceUser> oldUsers = userService.getAttendanceUserByGroupAndYearAndMonth(group.getId(), year, month);
        Map<String, AttendanceUser> oldUserDayShiftMap = new HashMap<>();
        Map<String, List<AttendanceUser>> oldUserDayMap = new HashMap<>();
        Map<String, AttendanceUser> oldUserDayShiftDeleteMap = new HashMap<>();
        if (!CollectionUtils.isEmpty(oldUsers)) {
            oldUsers.forEach(e -> {
                oldUserDayShiftMap.put(getUserDayShiftKey(e.getGroupId(), e.getUserId(), e.getShiftId(), e.getAttendanceDay()), e);
            });
            oldUserDayMap = oldUsers.stream().collect(Collectors.groupingBy(e -> getUserDayKey(e.getGroupId(), e.getUserId(), e.getAttendanceDay())));
        }
        XSSFRow dateRow = sheet.getRow(userNameRowIndex);
        errorMessage = importDateCheck(dateRow, dayBeanList, errorMessage, sheet.getSheetName());
        if (!CollectionUtils.isEmpty(errorMessage)) {
            return errorMessage;
        }
        for (int i = 4; i < sheet.getLastRowNum() + 1; i++) {
            XSSFRow row = sheet.getRow(i);
            if (row == null) {
                continue;
            }
            if (row.getCell(0) == null || StringUtils.isBlank(AttendanceDayUtils.getCellStringValue(row.getCell(0)))) {
                errorMessage.add(String.format(sheet.getSheetName() + "第{%s}行:人员姓名不能为空", i + 1));
                continue;
            }
            String userName = AttendanceDayUtils.getCellStringValue(row.getCell(0));
            if (riskImportService.isNum(userName)) {
                userName = riskImportService.getNumberString(userName);
            }
            Long userId = userNameIdMap.get(userName);
            if (userId == null) {
                errorMessage.add(String.format(sheet.getSheetName() + "第{%s}行:该考勤组最新配置无此人员", i + 1));
                continue;
            }
            //读取当前行各列排班
            boolean rowFlag = false;
            for (AttendanceDayBean dayBean : dayBeanList) {
                boolean listFlag = false;
                if (row.getCell(dayBean.getDay()) == null || StringUtils.isBlank(AttendanceDayUtils.getCellStringValue(row.getCell(dayBean.getDay())))) {
                    continue;
                }
                String shiftNameStr = AttendanceDayUtils.getCellStringValue(row.getCell(dayBean.getDay())).replace("，", ",");
                List<String> shiftNames = Splitter.on(Constant.SPLIT_COMMA).trimResults().splitToList(shiftNameStr);
                for (int j = 0; j < shiftNames.size(); j++) {
                    String shiftName = shiftNames.get(j);
                    if (riskImportService.isNum(shiftName)) {
                        shiftName = riskImportService.getNumberString(shiftName);
                    }
                    if (shiftNameMap.get(shiftName) == null) {
                        errorMessage.add(String.format(sheet.getSheetName() + "第{%s}行,第{%s}列:考勤组最新配置不包含该考勤班次{%s}", i + 1, dayBean.getDay() + 1, shiftName));
                        rowFlag = true;
                        listFlag = true;
                        continue;
                    }
                    AttendanceShift shift = shiftNameMap.get(shiftName);
                    if (shift.getBreakFlag().intValue() == 1 && shiftNames.size() > 1) {
                        errorMessage.add(String.format(sheet.getSheetName() + "第{%s}行,第{%s}列:休息班次不可与其他班次同时填写", i + 1, dayBean.getDay() + 1, shiftName));
                        rowFlag = true;
                        listFlag = true;
                        continue;
                    }
                    AttendanceUser user = new AttendanceUser();
                    String key = getUserDayShiftKey(group.getId(), userId, shift.getId(), dayBean.getDay());
                    if (oldUserDayShiftMap.get(key) != null) {
                        user = oldUserDayShiftMap.get(key);
                    }
                    user.setGroupId(group.getId());
                    user.setUserId(userId);
                    user.setShiftId(shift.getId());
                    user.setAttendanceYear(dayBean.getYear());
                    user.setAttendanceMonth(dayBean.getMonth());
                    user.setAttendanceDay(dayBean.getDay());
                    user.setAttendanceWeek(dayBean.getWeekDay());
                    user.setAttendanceFlag(AttendanceFlagEnum.EXCEL.getValue());
                    userList.add(user);
                    newUserDayShiftMap.put(getUserDayShiftKey(group.getId(), userId, shift.getId(), dayBean.getDay()), user);
                }
                //如果excel在改天填写数据 需要将该天排好班的数据单独保存 方便后面删除不需要的数据
                List<AttendanceUser> userMapList = oldUserDayMap.get(getUserDayKey(group.getId(), userId, dayBean.getDay()));
                if (!CollectionUtils.isEmpty(userMapList) && !listFlag) {
                    userMapList.forEach(u -> {
                        oldUserDayShiftDeleteMap.put(getUserDayShiftKey(u.getGroupId(), u.getUserId(), u.getShiftId(), u.getAttendanceDay()), u);
                    });
                }
            }
            //该行有异常 则忽略
            if (rowFlag) {
                continue;
            }
        }
        //删除不需要的就排班数据
        if (!CollectionUtils.isEmpty(oldUserDayShiftDeleteMap)) {
            for (Map.Entry<String, AttendanceUser> entry : oldUserDayShiftDeleteMap.entrySet()) {
                AttendanceUser u = entry.getValue();
                if (newUserDayShiftMap.get(entry.getKey()) == null) {
                    u.setDeleteFlag(DeleteFlag.DELETED.getCode());
                    userList.add(u);
                }
            }
        }
        if (!CollectionUtils.isEmpty(userList) && CollectionUtils.isEmpty(errorMessage)) {
            userService.saveOrUpdateBatch(userList);
        }
        return errorMessage;
    }

    private String getUserDayKey(Long groupId, Long userId, Integer day) {
        return groupId + "-" + userId + "-" + "-" + day;
    }

    private String getUserDayShiftKey(Long groupId, Long userId, Long shiftId, Integer day) {
        return groupId + "-" + userId + "-" + shiftId + "-" + day;
    }

    private List<String> importDateCheck(XSSFRow row, List<AttendanceDayBean> dayBeanList, List<String> errorMessage, String sheetName) {
        for (AttendanceDayBean dayBean : dayBeanList) {
            //读取日期行
            if (row.getCell(dayBean.getDay()) == null || StringUtils.isBlank(AttendanceDayUtils.getCellStringValue(row.getCell(dayBean.getDay())))) {
                errorMessage.add(String.format(sheetName + "第{%s}行,第{%s}列:日期不能为空", (userNameRowIndex + 1), (dayBean.getDay() + 1)));
                continue;
            }
            String titleStr = AttendanceDayUtils.getCellStringValue(row.getCell(dayBean.getDay()));
            try {
                String[] split = titleStr.split("/");
                int year = Integer.valueOf(split[0]);
                int month = Integer.valueOf(split[1]);
                int day = Integer.valueOf(split[2]);
                if (year != dayBean.getYear() || month != dayBean.getMonth() || day != dayBean.getDay()) {
                    errorMessage.add(String.format(sheetName + "第{%s}行,第{%s}列:年月日不正确,请填写正确的日期", (userNameRowIndex + 1), (dayBean.getDay() + 1)));
                }
            } catch (NumberFormatException e) {
                errorMessage.add(String.format(sheetName + "第{%s}行,第{%s}列:请填写正确的日期", (userNameRowIndex + 1), (dayBean.getDay() + 1)));
            }
        }
        return errorMessage;
    }

    @Override
    public SXSSFWorkbook exportUserExcel(Integer templateFlag, Integer year, Integer month, Long groupId) {
        SXSSFWorkbook workbook = new SXSSFWorkbook();
        List<AttendanceGroup> groupList = new ArrayList<>();
        //获取各个考勤组最近的配置讯息
        if (groupId == null) {
            groupList = groupService.getLastGroupList();
        } else {
            AttendanceGroup group = groupMapper.selectById(groupId);
            if (group != null) {
                groupList = Lists.newArrayList(group);
            }
        }
        if (CollectionUtils.isEmpty(groupList)) {
            throw new IllegalArgumentException("请先配置考勤组信息");
        }
        if (year == null || month == null) {
            LocalDateTime dateTime = LocalDateTime.now();
            year = dateTime.getYear();
            month = dateTime.getMonthValue();
        }
        boolean dateFlag = AttendanceDayUtils.getDateCheckFlag(year, month);
        Map<Long, AttendanceGroupShiftBean> shiftMap = shiftService.getShiftBeanMapFromGroup(null);
        for (AttendanceGroup group : groupList) {
            workbook = createExportSheetData(templateFlag, workbook, group, year, month, dateFlag, shiftMap);
        }
        return workbook;
    }


    private SXSSFWorkbook createExportSheetData(Integer templateFlag, SXSSFWorkbook workbook, AttendanceGroup group, int year, int month, boolean dateFlag, Map<Long, AttendanceGroupShiftBean> shiftMap) {
        //创建sheet
        SXSSFSheet sheet = workbook.createSheet(group.getGroupName());
        // 合并单元格 参数1：起始行 参数2：终止行 参数3：起始列 参数4：终止列
        List<AttendanceDayBean> dayBeanList = AttendanceDayUtils.getDayByMonth(year, month);
        //sheet第1行
        CellRangeAddress region = new CellRangeAddress(0, 0, (short) 0, (short) dayBeanList.size());
        sheet.addMergedRegion(region);
        SXSSFRow row1 = sheet.createRow(0);
        row1.setHeightInPoints(20);
        SXSSFCell cell0 = row1.createCell(0);
        cell0.setCellValue(group.getGroupName() + "排班表");
        cell0.setCellStyle(RiskEvalExcelUtil.title(workbook, false, 14));
        //sheet第2行
        CellRangeAddress hintRegion = new CellRangeAddress(1, 1, (short) 0, (short) dayBeanList.size());
        sheet.addMergedRegion(hintRegion);
        SXSSFRow row2 = sheet.createRow(1);
        SXSSFCell cell01 = row2.createCell(0);
        cell01.setCellValue("说明: \n" +
                "1、时间信息默认为导出前页面上的月份时间，时间格式请勿在表格中修改！\n" +
                "2、请在每一天日期中填写当前考勤组中的班次名称,即第3行中的班次名称.\n" +
                "3、一个员工如果一天有多个班，请用逗号分隔班次名称。例如：白班,晚班.");
        cell01.setCellStyle(RiskEvalExcelUtil.text(workbook, 11, true));
        //sheet第3行
        CellRangeAddress shiftRegion = new CellRangeAddress(2, 2, (short) 0, (short) dayBeanList.size());
        sheet.addMergedRegion(shiftRegion);
        SXSSFRow row3 = sheet.createRow(2);
        SXSSFCell ce02 = row3.createCell(0);
        Map<Long, AttendanceGroupShiftBean> shiftBeanMap = shiftService.getShiftBeanMapFromGroup(group);
        if (CollectionUtils.isEmpty(shiftBeanMap)) {
            throw new IllegalArgumentException("考勤组[" + group.getGroupName() + "],未设置考勤班次");
        }
        String s = "当前考勤组排班信息:";
        for (AttendanceGroupShiftBean shiftBean : shiftBeanMap.values()) {
            s += shiftBean.getShiftName() + "  ";
        }
        ce02.setCellValue(s);
        ////sheet第4行
        SXSSFRow row4 = sheet.createRow(3);
        SXSSFCell cell04 = row4.createCell(0);
        cell04.setCellValue("姓名");
        //本月年份
        for (int i = 0; i < dayBeanList.size(); i++) {
            AttendanceDayBean dayBean = dayBeanList.get(i);
            SXSSFCell celli = row4.createCell(i + 1);
            celli.setCellValue(dayBean.getYear() + "/" + dayBean.getMonth() + "/" + dayBean.getDay());
        }

        List<BaseUser> staffList = new ArrayList<>();
        //排班参与人员
        if (dateFlag) {
            //查询现在和以后的排查人员
            staffList = userService.getGroupStaffList(group, null, null);
        } else {
            //查询旧的排班人员
            staffList = userMapper.getAttendanceOldUserByGroupAndYearAndMonth(group.getId(), year, month);
        }
        List<AttendanceBaseUserExcelBean> userBeans = new ArrayList<>();
        if (!CollectionUtils.isEmpty(staffList)) {
            for (int i = 0; i < staffList.size(); i++) {
                SXSSFRow row = sheet.createRow(i + 3 + 1);
                SXSSFCell cell = row.createCell(0);
                BaseUser user = staffList.get(i);
                cell.setCellValue(user.getRealName());
                userBeans.add(new AttendanceBaseUserExcelBean(user.getId(), user.getRealName(), i + 3 + 1));
            }
        }
        //创建下拉框
//        List<String> shiftNams = shiftBeanMap.values().stream().map(AttendanceGroupShiftBean::getOriginalName).collect(Collectors.toList());
//        String[] datas = shiftNams.toArray(new String[shiftNams.size()]);
//        AttendanceDayUtils.createCells(sheet, datas, 3, 3+staffList.size(), 1, dayBeanList.size());
        if (templateFlag != null && templateFlag.intValue() == 1) {
            //查询改考勤班组该月人员排班
            List<AttendanceUser> userList = userService.getAttendanceUserByGroupAndYearAndMonth(group.getId(), year, month);
            if (!CollectionUtils.isEmpty(userList) && !CollectionUtils.isEmpty(userBeans)) {
                Map<Long, AttendanceBaseUserExcelBean> userBeanMap = userBeans.stream().collect(Collectors.toMap(AttendanceBaseUserExcelBean::getUserId, e -> e));
                //按照人员id分组-考勤组中每个人有多条排班记录(如1-30号的记录)
                Map<Long, List<AttendanceUser>> userDaysMap = userList.stream().collect(Collectors.groupingBy(AttendanceUser::getUserId));
                for (Map.Entry<Long, List<AttendanceUser>> entry : userDaysMap.entrySet()) {
                    AttendanceBaseUserExcelBean userBean = userBeanMap.get(entry.getKey());
                    if (userBean != null) {
                        int rowIndex = userBean.getRowIndex();
                        SXSSFRow row = sheet.getRow(rowIndex);
                        List<AttendanceUser> users = userDaysMap.get(entry.getKey());
                        Map<Integer, List<AttendanceUser>> dayUserMap = users.stream().collect(Collectors.groupingBy(AttendanceUser::getAttendanceDay));
                        users.forEach(e -> {
                            //该人员当天的排班(一个人一天的排班有多个考勤班次)
                            List<AttendanceUser> dayUserList = dayUserMap.get(e.getAttendanceDay());
                            if (!CollectionUtils.isEmpty(dayBeanList)) {
                                SXSSFCell cell = row.createCell(e.getAttendanceDay());
                                String str = "";
                                for (AttendanceUser u : dayUserList) {
                                    if (shiftMap.get(u.getShiftId()) != null) {
                                        str = str + shiftMap.get(u.getShiftId()).getOriginalName() + ",";
                                    }
                                }
                                if (str.endsWith(",")) {
                                    str = str.substring(0, str.length() - 1);
                                }
                                cell.setCellValue(str);
                            }
                        });
                    }
                }
            }
        }
        return workbook;
    }
}
